package com.example.shop.common.service.impl;


import com.example.shop.common.service.FaceRecognitionService;
import com.example.shop.common.dto.face.FaceRecognitionReturnResult;
import com.example.shop.common.util.HttpURLConnectionHelper;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * 旷视平台
 */
@Service
public class FaceRecognitionServiceImpl implements FaceRecognitionService {

    @Value("${face-recognition.api-key}")
    private  String API_KEY;
    @Value("${face-recognition.api-secret}")
    private  String API_SECRET;
    @Value("${face-recognition.out-id}")
    private  String outerId;
    /**
     * 将响应的json字符串转换成对应的传输对象
     * @param json 请求后响应回来的json字符串
     * @param classBean 要转换的传输对象类
     * @return 返回转换结果（传输对象）
     */
    private Object toBean(String json,Class classBean) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        //以文本形式返回时间
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        //默认为true,即json字符串中不能含有java对象中不存在的属性。
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //所有成员字段都可以序列化 ,而不仅仅是公共字段(默认设置)
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //这里不能配置
        //如果配置下面这个，要求返回的是[类型,{对象json字符串}]
        //但是该网站返回的是{对象json字符串}
        //objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        return objectMapper.readValue(json,classBean);
    }

    /**
     *
     * @param url 请求url，默认是post请求
     * @param generalParams 请求的普通字段参数
     * @param filesParams 请求的文件字段参数
     * @return 请求失败，则返回null
     * @throws Exception
     */
    private byte[] request(URL url,Map<String,String> generalParams,Map<String,byte[]> filesParams) throws Exception {
        HttpURLConnectionHelper http = new HttpURLConnectionHelper(url);
        //使用默认的post请求头
        http.DefaultPostSetHeader();
        //普通字段
        HashMap<String, String> requestGeneralParams = new HashMap<>();
        requestGeneralParams.put("api_key",API_KEY);
        requestGeneralParams.put("api_secret",API_SECRET);
        if(generalParams!=null){
            Set<Map.Entry<String, String>> entries = generalParams.entrySet();
            for(Map.Entry<String, String> entry:entries){
                requestGeneralParams.put(entry.getKey(),entry.getValue());
            }
        }
        //文件字段
        Map<String,byte[]> requestFilesParams=new HashMap<>();
        if(filesParams!=null){
            Set<Map.Entry<String, byte[]>> fileEntries = filesParams.entrySet();
            for(Map.Entry<String, byte[]> entry:fileEntries){
                requestFilesParams.put(entry.getKey(),entry.getValue());
            }
        }
        //设置请求的字段参数
        http.setPostRequestParameters(requestGeneralParams,requestFilesParams);
        //进行连接
        http.connect();
        //处理连续返回的结果
        if(http.getResponseState() == HttpURLConnection.HTTP_OK) {
            return http.getResponseBody();
        }else{
            return null;
        }
    }
    /**
     * 识别出该人脸中的所有人脸信息
     * @param faceBase64 人脸图片的base64字符串
     * @return 识别出所有人脸信息则返回，如果识别不出，则返回null
     */
    public ImgFaces detectFace(String faceBase64){
        if(faceBase64==null){
            return null;
        }
        Base64.Decoder base64Decoder = Base64.getDecoder();
        try {
            byte[] faceByte = base64Decoder.decode(faceBase64);
            URL url = new URL("https://api-cn.faceplusplus.com/facepp/v3/detect");
            //文件字段
            HashMap<String, byte[]> filesParams = new HashMap<>();
            filesParams.put("image_file",faceByte);
            //对连接结果进行处理
            byte[] responseBody = request(url, null, filesParams);
            if(responseBody!=null){
                //拿到图片中所有人脸的信息
                return (ImgFaces) toBean(new String(responseBody),ImgFaces.class);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public FaceRecognitionReturnResult faceRecognition(String faceBase64) {
        Base64.Decoder base64Decoder = Base64.getDecoder();
        try{
            byte[] faceByte = base64Decoder.decode(faceBase64);
            URL url = new URL("https://api-cn.faceplusplus.com/facepp/v3/search");
            //普通字段
            HashMap<String, String> generalParams = new HashMap<>();
            generalParams.put("outer_id",outerId);
            //文件字段
            Map<String,byte[]> filesParams=new HashMap<>();
            filesParams.put("image_file",faceByte);
            byte[] responseBody = request(url, generalParams, filesParams);
            //将返回的响应体转换为人脸识别结果对象
            if(responseBody!=null){
                RecognitionFaceResult results = (RecognitionFaceResult) toBean(new String(responseBody), RecognitionFaceResult.class);
                Result result =results.getResults().get(0);
                return new FaceRecognitionReturnResult(result.getUserId(), result.getConfidence());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public  int detectFaceNum(String faceBase64){
        ImgFaces imgFaces = detectFace(faceBase64);
        if(imgFaces!=null)
            return imgFaces.getFacesNum();
        return -1;
    }

    @Override
    public List<String> detectFaceToken(String faceBase64) {
        ImgFaces imgFaces = detectFace(faceBase64);
        if(imgFaces!=null){
            List<FaceToken> faceTokens = imgFaces.getFaceTokens();
            List<String> faceTokenList = new ArrayList<>();
            for(FaceToken ft: faceTokens){
                faceTokenList.add(ft.getFaceToken());
            }
            return faceTokenList;
        }
        return null;
    }

    @Override
    public boolean userIdentificationFace(String userId, String faceToken) throws Exception {
        if(StringUtils.isEmpty(userId) || faceToken == null){
            return false;
        }
        URL url = new URL("https://api-cn.faceplusplus.com/facepp/v3/face/setuserid");
        //普通字段
        HashMap<String, String> generalParams = new HashMap<>();
        generalParams.put("face_token",faceToken);
        generalParams.put("user_id",userId);
        //对请求的结果进行处理
        byte[] responseBody = request(url, generalParams, null);
        if(responseBody!=null){
            return true;
        }
        return false;
    }

    @Override
    public boolean removeFaceToSet(String faceToken) throws Exception {
        if(faceToken==null){
            return false;
        }
        URL url = new URL("https://api-cn.faceplusplus.com/facepp/v3/faceset/removeface");
        //普通字段
        HashMap<String, String> generalParams = new HashMap<>();
        generalParams.put("outer_id",outerId);
        generalParams.put("face_tokens",faceToken);
        //对连接的结果进行处理
        byte[] responseBody = request(url, generalParams, null);
        if(responseBody!=null){
            return true;
        }
        return false;
    }


    @Override
    public boolean addFaceToSet(String faceToken) throws Exception {
        if(faceToken==null){
            return false;
        }
        URL url = new URL("https://api-cn.faceplusplus.com/facepp/v3/faceset/addface");
        //普通字段
        HashMap<String, String> generalParams = new HashMap<>();
        generalParams.put("outer_id",outerId);
        generalParams.put("face_tokens",faceToken);
        //对连接的结果进行处理
        byte[] responseBody = request(url, generalParams, null);
        if(responseBody!=null){
            return true;
        }
        return false;
    }

    /**
     * 删除人脸库
     * @param outerId 人脸库的唯一标识名
     * @return 返回删除是否成功，成功返回true
     */
    public boolean deleteFacesSet(String outerId) throws Exception {
        URL url = new URL("https://api-cn.faceplusplus.com/facepp/v3/faceset/delete");
        //普通字段
        HashMap<String, String> generalParams = new HashMap<>();
        generalParams.put("outer_id",outerId);
        /**
         * 删除时是否检查FaceSet中是否存在face_token，默认值为1
         * 0：不检查
         * 1：检查
         */
        generalParams.put("check_empty","0");
        //对连接的结果进行处理
        byte[] responseBody = request(url, generalParams, null);
        if(responseBody!=null){
            return true;
        }
        return false;
    }

    /**
     * 请求旷视平台创建人脸库
     * @param outerId 人脸库的唯一标识名
     * @return 返回创建成功是否，成功为true
     */
    public boolean createFacesSet(String outerId) throws Exception {
        URL url = new URL("https://api-cn.faceplusplus.com/facepp/v3/faceset/create");
        //普通字段
        HashMap<String, String> generalParams = new HashMap<>();
        generalParams.put("outer_id",outerId);
        //对连接的结果进行处理
        byte[] responseBody = request(url, generalParams, null);
        if(responseBody!=null){
            return true;
        }
        return false;
    }
    public static void main(String[] args) {
        FaceRecognitionServiceImpl faceRecognitionService = new FaceRecognitionServiceImpl();

//        System.out.println(faceRecognitionService.createFacesSet(faceRecognitionService.outerId));
    }



    //存放图片中的所有人脸信息
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    static class ImgFaces{
        @JsonProperty("face_num")
        @JsonAlias("facesNum")
        private int facesNum;
        //存放识别图片中所有人脸的faceToken。faceTokens在旷视平台中唯一标识该人脸, 且按可信度排序从高到低
        @JsonProperty("faces")
        @JsonAlias("faceTokens")
        private List<FaceToken> faceTokens;

        @Override
        public String toString() {
            return "ImgFaces{" +
                    "facesNum=" + facesNum +
                    ", faceTokens=" + faceTokens +
                    '}';
        }
    }
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    static class FaceToken{
        @JsonProperty("face_token")
        @JsonAlias("faceToken")
        private String faceToken;

        @Override
        public String toString() {
            return "FaceToken{" +
                    "faceToken='" + faceToken + '\'' +
                    '}';
        }
    }
    //存放旷视人脸识别平台的识别结果
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    static class RecognitionFaceResult {
        @JsonProperty("results")
        private List<Result> results;

        @Override
        public String toString() {
            return "RecognitionFaceResult{" +
                    "results=" + results +
                    '}';
        }
    }
    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    static class Result {
        @JsonProperty("user_id")
        @JsonAlias("userId")
        //该人脸唯一标识该用户
        private String userId;
        @JsonProperty("face_token")
        @JsonAlias("faceToken")
        //该人脸的唯一标识
        private String faceToken;
        //识别出来的人脸与该标识的用户匹配的可信度
        private float confidence;

        @Override
        public String toString() {
            return "Result{" +
                    "userId='" + userId + '\'' +
                    ", faceToken='" + faceToken + '\'' +
                    ", confidence=" + confidence +
                    '}';
        }
    }
}
